package vn.mahjonggame.game.request;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.log4j.Logger;

import vn.mahjonggame.game.Mahjong;
import vn.mahjonggame.game.MahjongExtension;
import vn.mahjonggame.metadata.GameActionType;
import vn.mahjonggame.metadata.MahjongCache;
import vn.mahjonggame.metadata.Player;
import vn.mahjonggame.metadata.MObject;
import vn.mahjonggame.metadata.Response;
import vn.mahjonggame.metadata.RoomVarName;
import vn.mahjonggame.metadata.Tile;
import vn.mahjonggame.metadata.TileSet;
import vn.mahjonggame.metadata.WaitType;
import vn.mahjonggame.platform.PlatformConfig;

import com.smartfoxserver.v2.entities.Room;
import com.smartfoxserver.v2.entities.User;
import com.smartfoxserver.v2.entities.data.ISFSObject;
import com.smartfoxserver.v2.entities.data.SFSObject;
import com.smartfoxserver.v2.extensions.BaseClientRequestHandler;
import com.smartfoxserver.v2.extensions.ExtensionLogLevel;

public class CallChiHandler extends BaseClientRequestHandler {

	@Override
	public void handleClientRequest(User user, ISFSObject params) {
		
		final MahjongExtension ext = (MahjongExtension) getParentExtension();
		
		callChi(ext, user, params);
	}
	
	public void callChi(final MahjongExtension ext, final User user, ISFSObject params){		
		setParentExtension(ext);
		Mahjong mahjong = ext.getMahjong();
		final Player player = mahjong.getPlayerById(user.getId());
		List<User> users = user.getLastJoinedRoom().getUserList();
		Room room = ext.getGameRoom();
		Logger logger = mahjong.getLogger();
		
		/*
		 * Cancel the player's timer
		 */
		player.cancelTimer();
		
		int bonusTime = params.getInt(MObject.bonusTime.toString());		
		List<Integer> chiTiles = (List<Integer>)params.getIntArray(MObject.chiTiles.toString());
		
		List<Integer> tileIds = new ArrayList<Integer>(chiTiles);
		Collections.sort(tileIds);
		
		Player thrownPlayer = mahjong.getThrownPlayer();
		Player playerInTurn = mahjong.getPlayerInTurn();
		
		List<Tile> playerRightTiles = player.getRightTiles();
		List<Tile> playerLeftTiles = player.getLeftTiles();		
				
		Tile tile = thrownPlayer.getJustThrownTile();
				
		logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "justThrownTile: " + tile.toString()));
		
		List<List<Tile>> actualChiTiles = player.checkChi(tile);
					
		/*
		 * Check valid CHI SET
		 */
		if(!mahjong.tilesArrayToTileIdsArray(actualChiTiles).contains(tileIds)){		
			logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "The CHI set is not matched."));
			return;
		}
		
		mahjong.setCanCallChiPlayer(null);
		Player player1 = mahjong.getCanCallPonPlayer();
		Player player2 = mahjong.getCanCallOpenKanPlayer();
		
		/*
		 * Check if another player can call PON/PUBLIC KAN/RON
		 */
		if(mahjong.getCanCallPonPlayer() != null
				|| mahjong.getCanCallOpenKanPlayer() != null
				|| mahjong.getCanCallRonPlayers().size() > 0){
			
			mahjong.setCallingChiPlayer(player);
			
			Response.Builder response = new Response.Builder();
			response.position(player.getPlayerPosition())
					.turn(player.getPlayerPosition());			
			/*
			 * Cache info to be used in case RON/OPENKAN/PON is ignored
			 */
			player.getCache().put(MahjongCache.bonusTime.toString(), bonusTime);
			player.getCache().put(MahjongCache.chiTiles.toString(), chiTiles);
			player.cancelTimer();
						
			send(GameActionType.waitting.toString(), response.build().getSFSObject(), user);			
			logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "Wait for another RON/KAN/PON..."));
			return;
		}
		
		/*
		 * Move the thrown tile to the righttiles
		 */
		playerRightTiles.add(tile);
		
		/*
		 * Add the CHI tiles to the right hand and remove the correspond tile on the left hand 
		 */
		for(int i = 0; i < tileIds.size(); i++){
			int tileId = tileIds.get(i);
			Tile tileTmp = mahjong.getTileById(tileId);
			playerRightTiles.add(tileTmp);
			playerLeftTiles.remove(tileTmp);
		}		
		
		logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "leftTiles: " + player.getLeftTiles()));		
		logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "rightTiles: " + player.getRightTiles()));				
		logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "tileSet: " + player.logTileSet()));
		
		/*
		 * The tile of player is become public
		 */
		player.setPublic(true);		
		
		/*
		 * Response
		 */
		Response.Builder response = new Response.Builder();
		Response.Builder chiObject = new Response.Builder();
		
		chiObject.losePos(thrownPlayer.getPlayerPosition())
				.winPos(player.getPlayerPosition())
				.loseTile(tile.getId())
				.winTile(chiTiles);
		
		response.CHI(chiObject.build().getSFSObject())
				.turn(player.getPlayerPosition())
				.turnTime(player.getTurnTime()/1000)
				.bonusTime(player.getBonusTime()/1000);
		
		send(GameActionType.callChi.toString(), response.build().getSFSObject(), users);
				
		ext.addAction(user, GameActionType.callChi.toString());
		
		player.setHasThrown(false);
		player.setHasPicked(true);
		
		player.updateBonusTime();
		
		logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "Bonus time from client: " + bonusTime * 1000));			
		logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "Bonus time from server: " + player.getBonusTime()));
		logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "startTime: " + player.getStartTime()));
		logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "leftTime: " + (player.getEndTime() - player.getStartTime())));
				
		mahjong.setPlayerInTurn(player);
		mahjong.resetTileSet();
		
		logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "chiTiles: " + chiTiles));
		logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "actualChiTiles: " + actualChiTiles));
		
		if(player.isDisconnect() || Boolean.valueOf(room.getVariable(RoomVarName.is_auto.toString()).getStringValue())){
			/*
			 * Wait 5 second. If player does not thrown the tile, auto thrown the tile
			 */		
						
			final Response.Builder nextParams = new Response.Builder();
			int size = player.getLeftTiles().size();
			tile = player.getLeftTiles().get(size - 1);
			nextParams.tile(tile.getId());
			
			int delay = player.getTurnTime() + player.getBonusTime();	
			/*
			 * Only wait 1 second if the player is disconnected
			 */
			if(player.isDisconnect()){
				delay = 1000;
			}
			logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "isDisconnect: " + player.isDisconnect()));			
			logger.info(mahjong.log(room, player, GameActionType.callChi.toString(), "Calling throw handler: " + delay));
			Timer timer = player.getTimer();
			timer.schedule(new TimerTask() {
				  @Override
				  public void run() {
					  if(!player.isHasThrown()){
						  ThrowTileHandler throwTileHandler = new ThrowTileHandler();					  
						  throwTileHandler.throwTile(ext, user, nextParams.build().getSFSObject(), true, false);
					  }								
				  }
			}, delay);
		}
	}
}
